package com.weizhu.swufer.core.server;

import cn.hutool.core.collection.CollUtil;
import com.weizhu.swufer.autoconfiguration.RpcInfoScanner;
import com.weizhu.swufer.constant.SwuferConstant;
import com.weizhu.swufer.core.client.DefaultGenericService;
import com.weizhu.swufer.core.client.GenericService;
import com.weizhu.swufer.core.client.ReferenceConfig;
import com.weizhu.swufer.core.client.ReferenceProxyHandler;
import com.weizhu.swufer.core.cluster.Cluster;
import com.weizhu.swufer.core.entity.RpcBaseInfo;
import com.weizhu.swufer.core.rpc.RpcEngine;

import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;


public class SwuferBootstrap{


    private static volatile SwuferBootstrap instance;

    private List<RpcBaseInfo> rpcBaseInfoList;

    private static Properties properties;

    private RpcEngine rpcEngine;

    private SwuferBootstrap(Properties properties){
        SwuferBootstrap.properties = properties;
        this.rpcEngine = RpcEngine.getInstance();
        rpcEngine.initEngine(properties);
    }


    public static SwuferBootstrapBuilder newBuilder(){
        return new SwuferBootstrapBuilder();
    }

    public static class SwuferBootstrapBuilder{

        private List<RpcBaseInfo> rpcBaseInfoList = new ArrayList<>();

        SwuferBootstrapBuilder(){
            properties = new Properties();
            properties.setProperty(SwuferConstant.PROPERTIES_WEIGHT,String.valueOf(SwuferConstant.DEFAULT_WEIGHT));
            properties.setProperty(SwuferConstant.PROPERTIES_PORT,String.valueOf(SwuferConstant.DEFAULT_PORT));
        }

        public SwuferBootstrapBuilder registry(String address){
            properties.setProperty(SwuferConstant.PROPERTIES_REGISTRY_ADDRESS,address);
            return this;
        }

        public SwuferBootstrapBuilder port(Integer port){
            properties.setProperty(SwuferConstant.PROPERTIES_PORT,String.valueOf(port));
            return this;
        }

        public SwuferBootstrapBuilder cluster(String cluster){
            properties.setProperty(SwuferConstant.PROPERTIES_CLUSTER,cluster);
            return this;
        }

        public SwuferBootstrapBuilder cluster(Class<?> cluster){
            properties.setProperty(SwuferConstant.PROPERTIES_CLUSTER,cluster.getName());
            return this;
        }

        public SwuferBootstrapBuilder loadBalance(String loadBalancer){
            properties.setProperty(SwuferConstant.PROPERTIES_LOADBALANCER,loadBalancer);
            return this;
        }

        public SwuferBootstrapBuilder loadBalance(Class<?> loadBalancer){
            properties.setProperty(SwuferConstant.PROPERTIES_LOADBALANCER,loadBalancer.getName());
            return this;
        }

        public SwuferBootstrapBuilder scanRpcService(String packagePath) throws Exception {
            RpcInfoScanner rpcInfoScanner = new RpcInfoScanner(packagePath);
            rpcInfoScanner.scanRpcBaseInfo();
            rpcInfoScanner.scanFilter(packagePath);
            rpcInfoScanner.scanFilter("com.weizhu.swufer.core.filter");
            this.rpcBaseInfoList = rpcInfoScanner.getRpcBaseInfoList();
            return this;
        }

        public SwuferBootstrap buildBootstrap(){
            SwuferBootstrap bootstrap = SwuferBootstrap.getInstance(properties);
            bootstrap.setRpcBaseInfoList(this.rpcBaseInfoList);
            return bootstrap;
        }
    }


    public static SwuferBootstrap getInstance(){

        return instance;
    }

    public static SwuferBootstrap getInstance(Properties properties) {
        if (instance == null) {
            synchronized (SwuferBootstrap.class) {
                if (instance == null) {
                    instance = new SwuferBootstrap(properties);
                    instance.init();
                }
            }
        }
        return instance;
    }

    public void init() {

    }

    public void start() throws IOException {


        System.err.println("<===========Swufer RPC 启动，开始发现服务=================>");

        if (CollUtil.isEmpty(rpcBaseInfoList)){
            System.err.println("<===========没有Swufer RPC服务=================>");
        }else {
            rpcEngine.registerRpcService(rpcBaseInfoList);
            rpcEngine.start();
        }

    }

    public void stop() {

    }

    public Object getReference(ReferenceConfig referenceConfig){

        Class<?> tClass = referenceConfig.gettClass();
        if (tClass == GenericService.class){
            return new DefaultGenericService(referenceConfig);
        }
        return Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass},
                new ReferenceProxyHandler(referenceConfig));

    }

    public <T> T getReference(Class<T> tClass, ReferenceConfig referenceConfig){
        if(tClass != referenceConfig.gettClass()){
            throw new IllegalStateException("error: tClass != referenceConfig.tClass");
        }
        if (tClass == GenericService.class){
            return (T) new DefaultGenericService(referenceConfig);
        }
        Object proxy = Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass},
                new ReferenceProxyHandler(referenceConfig));
        return (T) proxy;
    }

    public List<RpcBaseInfo> getRpcBaseInfoList() {
        return rpcBaseInfoList;
    }

    public void setRpcBaseInfoList(List<RpcBaseInfo> rpcBaseInfoList) {
        this.rpcBaseInfoList = rpcBaseInfoList;
        rpcBaseInfoList.forEach(
                x->x.setPort(Integer.parseInt(properties.getProperty(SwuferConstant.PROPERTIES_PORT))));
        rpcBaseInfoList.forEach(
                x->x.setWeight(Integer.parseInt(properties.getProperty(SwuferConstant.PROPERTIES_WEIGHT))));
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public RpcEngine getRpcEngine() {
        return rpcEngine;
    }

    public void setRpcEngine(RpcEngine rpcEngine) {
        this.rpcEngine = rpcEngine;
    }
}
